feat: add Upload-Post integration for social media publishing#7
Open
mutonby wants to merge 1 commit into
Open
Conversation
Add uploadpost_publisher tool that publishes finished videos, photos, documents, and text to 11 social platforms (Instagram, TikTok, YouTube, LinkedIn, Facebook, X, Threads, Pinterest, Bluesky, Reddit, Google Business) via a single API call through Upload-Post. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Author
|
@calesthio I think it's the missing piece to complete the picture. Let me know if you have any questions. |
|
This is a good initiative @mutonby. |
jahai
added a commit
to jahai/OpenMontage
that referenced
this pull request
May 9, 2026
…alesthio#8 from Phase 2 lessons Banks two patterns that surfaced during Phase 2. Real Phase-3+ discipline value; both now documented as canonical AUDIT_PATTERNS reference. Pattern calesthio#7: Test infrastructure must accommodate derived IDs. - Default gate satisfied: multiple Phase 2 test files hit the issue (test_audit_consult.py orphan YAMLs, test_audit.py needing cascading_delete with synthetic IDs, test_thumbnails.py similar, test_vision_anthropic.py with TRACKED_API_CALL_IDS). - Production ID derivation is correct (deterministic, content-aware, collision-resistant) but makes IDs test-hostile. ~80 lines of cleanup logic for ~7 audit-consult tests; growing with each new Wave-B-related test suite. - Rule: modules that derive IDs internally must accept _id_override keyword-only param (FOR TESTING ONLY). Tests pass test-prefixed IDs; cascading_delete handles cleanup uniformly. - v0.6 amendment landed _id_override on audit.create_audit_session + audit.capture_verdict; Pattern calesthio#7 names the discipline canonically so future Phase 3+ derived-ID modules opt in. Pattern calesthio#8: Content-matching specification must be tightened against project-specific content (preventive promotion per gate amendment). - v0.6 review caught _SAFETY_REFUSAL_RE matching legitimate critical evaluations ("I cannot recommend this for hero promotion because the apparatus geometry is unclear"). Single occurrence; promoted preventively because the failure surface is broader than the single bug. - Promotion note explicit: future content-matching specifications (rubric criteria parsing, future provider-specific refusal patterns when Perplexity / ChatGPT / Gemini adapters land, cross-AI capture relevance-binding heuristics, filepath-pattern recovery in walker) face the same risk class against the same project content domain (H#3 reenactment, addiction themes, behavioral-conditioning register). - Rule: third bucket of test cases mandatory — "looks-like-target- but-isn't" cases drawn from project content. Generic positive + generic negative + project-specific-negative. - Verb-aware patterns over blanket prefix matching where applicable (per _SAFETY_REFUSAL_RE tightening precedent). Updated timestamp banks the v0.7 amendment of the discipline doc itself. Tests: 16/16 still green (doc-only change). Phase 2 acceptance bridge gate unchanged: rubric authoring + one real Wave B firing still required before Phase 3 Wave 1 code starts. This is preparatory discipline-banking work that compounds for Phase 3+ test infrastructure. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
jahai
added a commit
to jahai/OpenMontage
that referenced
this pull request
May 13, 2026
…forcement calesthio#3 + Banking principle calesthio#7 + Phase 2.5 conftest fix promoted to MUST-DO Five additions documenting the cleanup-leak class surfaced in this session's diagnostic side-thread: 1. New Pattern calesthio#8 reinforcement entry calesthio#3 — test cleanup leak class. Two confirmed instances (test_audit_sessions audit_sessions leak + test_vision_anthropic api_calls leak). Pattern: when test scope assumes "I know all the IDs I created" but production code creates derivative rows from test-injected data with its own SHA-derived IDs, cleanup silently leaves rows behind. 2. New Banking principle calesthio#7 — test isolation should be enforced at fixture level, not at cleanup discipline. Surfaces only when production queries (cost rollups, /healthz banners) become polluted enough to notice. 3. Phase 2.5 conftest+tmp_path fix promoted from deferred-candidate to MUST-DO before Wave 1 code starts. Added new entry at top of "Phase 3 territory" section with estimate (~2-4 hours), scope (16 existing test suites to migrate), and verification approach (state.db row count assertions before/after). 4. Updated existing "Test runner quirk" section's Phase 2.5 reference to point at the new MUST-DO framing instead of the prior deferred framing — keeps the doc internally consistent. 5. Updated header to reflect cleanup-leak class banking + a52ec90 api_calls cleanup commit reference. References: companion commit a52ec90 (api_calls cleanup execution). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
jahai
added a commit
to jahai/OpenMontage
that referenced
this pull request
May 15, 2026
Eliminates the cleanup-leak class (Pattern calesthio#8 reinforcement calesthio#3 / Banking principle calesthio#7) structurally by isolating test writes to tmp_path. Tests never touch production _data/state.db. Replaces the cleanup-discipline pattern (TRACKED_*_IDS + cascading_delete prefix) with fixture-level isolation. - migrations/env.py: TOOL_BUILD_ALEMBIC_URL env var override (conftest uses it to point Alembic at tmp_path during the template-DB construction). - tests/conftest.py (new): session-scoped template DB built once via Alembic upgrade head; per-test autouse isolated_db fixture copies the template, builds the canonical _data/ tree under tmp_path/projects/latent_systems/tool_build/, patches db.{DB_PATH,DATA_DIR,REPO_ROOT,TOOL_BUILD_DIR}, patches the 5 dependent-module snapshots (runtime, router_tail, retry_queue, thumbnails, watcher), auto-seeds tool-grammar configs from seeds/*.yaml. - 15 test files: `def test_main(): assert main() == 0` wrapper added before if __name__ block. Standalone `python tests/test_X.py` invocation preserved (uses production _data/, original cleanup-discipline behavior — fixture only applies under pytest). - 3 test files (test_audit_consult, test_thumbnails, test_vision_anthropic): module-level TEST_DIR snapshot replaced with _test_dir() function for lazy db.DATA_DIR evaluation. - test_router_tail.py: test_ingest_roundtrip renamed _ingest_roundtrip (pytest discovery + repo_root fixture mismatch); test_main skipped with rationale — real-repo integration test covered by standalone path. - SESSION_STARTER.md state-check step 4: script-loop → pytest. Verification: full suite 94 passed + 1 documented skip; production state.db row counts byte-identical pre/post. ~13s suite runtime (vs ~5s prior script-loop; isolation overhead acceptable). Phase 2.5 conftest non-negotiable item per Day 1 of sprint: COMPLETE.
jahai
added a commit
to jahai/OpenMontage
that referenced
this pull request
May 15, 2026
…ic action + audio assets
Three deliverables landed on Day 2 of the 7-day Phase 3 complete-the-
app sprint, all additive and verified via the Day 1 isolated_db
fixture (full suite 96 passed + 1 documented skip; production
state.db row counts byte-identical pre/post pytest run).
**Migration 0004** (additive — no temp-table-and-copy):
- notes_md_state (new) — F6 NOTES.md authorship state per
phase3_design_notes.md v0.2 schema sketch.
- cross_ai_captures ALTER + 7 columns + 2 indexes — F7 cross-AI
capture expansion per v0.2 design.
- hero_promotions ALTER + 4 nullable columns (verdict_id,
promoted_at, promoted_by, audit_session_id) — gap closure between
F5_MODAL_UX_DRAFT.md INSERT shape and v0.2 schema sketch which
didn't include them. Existing 3 production rows survive without
backfill; F5 enforces non-null at application layer.
- audio_assets (new) — rough-cut player prereq (Days 4-5). Tracks
narration mp3 files (EP1_section_N_para_P_voice_X<val>_take<N>.mp3)
with section + paragraph + variant + voice_profile + hash +
is_canonical for player playlist construction.
- constants.SUPPORTED_SCHEMA_VERSIONS extended to {0001..0004}.
**F5 hero promotion atomic action** per F5_MODAL_UX_DRAFT.md v1.2:
- dispatcher.hero_promote() — atomic file-COPY + DB-INSERT
transaction. Step 3 (F6 prompt fire) deferred (F6 lands Day 3);
graceful-degradation status 'deferred_f6_not_shipped'.
- dispatcher.hero_un_promote() — atomic file-MOVE
(winners/ -> _DEPRECATED_<sanitized>/) + DB-UPDATE. Reason
>= 5 chars + filesystem-safe sanitization per channel staple calesthio#12.
- POST /audit/render/<id>/promote + /un_promote endpoints in
app.py with 400/404/409/500 mapping based on error class.
- tests/test_hero_promotion.py — 14 scenarios covering positive,
project-specific looks-like-target-but-isn't (weak verdict,
no section, winners/ auto-create, path-traversal sanitization),
and negative (no render, no verdict, already-promoted, no
active promotion, sanitized-to-empty reason).
- Modal UI deferred to Day 6 per original Wave 1 plan.
**Audio asset first-class state.db support** (rough-cut player
prereq):
- audio_assets.py module: parse_audio_filename, ingest_audio_file
(idempotent on hash), rebuild_audio_cache (walks canonical
voice-profile tree, skips load-bearing validation filenames +
archived/_DEPRECATED_ paths), get_audio_assets_for_section
(paragraph-ordered, canonical_only filter), set_canonical_variant
(exclusive within slot).
- tests/test_audio_assets.py — 12 scenarios.
**Cascade order fix:** db.py _CASCADE_DELETE_ORDER hero_promotions
+ verdicts entries extended to `id LIKE ? OR render_id LIKE ?`
because hero_promote derives hashed promotion_id (Pattern calesthio#7 —
derived IDs don't carry test prefixes; OR-on-render_id catches
test-prefixed renders' promotions). conftest.py _ARTIFACT_SUBDIRS
extended with notes_md_state + audio_assets.
state.db.pre_0004_backup written locally before migration (per
migration boilerplate); NOT committed (local-only insurance).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds an
uploadpost_publishertool that lets OpenMontage publish finished videos, photos, documents, and text posts directly to 11 social platforms from the publish pipeline stage — no extra code, no per-platform OAuth setup.Supported platforms: Instagram, TikTok, YouTube, LinkedIn, Facebook, X (Twitter), Threads, Pinterest, Bluesky, Reddit, Google Business Profile.
How it works
UPLOADPOST_API_KEYin.env.uploadpost_publishertool is auto-discovered by the registry and becomes available in every pipeline's publish stage.Free tier: 10 uploads/month across all platforms.
What's included
tools/publishers/uploadpost_publisher.py— FullBaseToolimplementation with:POST /api/upload)POST /api/upload_photos)POST /api/upload_document)POST /api/upload_text)scheduled_date) and queue support (add_to_queue)dry_run()preflight checksskills/core/social-publishing.md— Layer 2 skill doc for agentsAll 10 pipeline publish stages updated with
uploadpost_publisherintools_availableAll 10 publish-director skills updated with "Direct Publishing" section
.env.exampleupdated withUPLOADPOST_API_KEYskills/INDEX.mdupdated withsocial_publishingcapability familyIntegration architecture
The tool follows the same patterns as existing API tools (e.g.,
veo_video): env-based API key,get_status()check,estimate_cost(),dry_run(), retry policy, and idempotency keys.Test plan
registry.discover()(appears in 67-tool list)capability_catalog()undersocial_publishingprovider_menu()with install instructionsdry_run()correctly reports missing API key and missing filesunavailablewithout API key,availablewith itAPI docs: https://docs.upload-post.com
🤖 Generated with Claude Code